﻿namespace Vibstudio.NetConfigurator.Engine
{
    #region Namespaces

    using System;
    using System.Collections.Generic;

    using Vibstudio.NetConfigurator.Common;
    using Vibstudio.NetConfigurator.Exceptions;
    using Vibstudio.NetConfigurator.Extensions;
    using Vibstudio.NetConfigurator.IoC;
    using Vibstudio.NetConfigurator.Model;

    #endregion

    public class ConfigurationManager
    {
        #region Fields

        private readonly bool _backup;

        private readonly Dictionary<string, IConfiguration> _configurators;

        private readonly string _rootPath;

        #endregion

        #region Ctor(s)

        private ConfigurationManager(string rootPath, bool backup)
        {
            _configurators = Container.Resolve<IConfiguration>();

            _rootPath = rootPath;
            _backup = backup;
        }

        #endregion

        #region Public Methods and Operators

        public static ConfigurationManager Setup(string rootPath, bool backup)
        {
            return new ConfigurationManager(rootPath, backup);
        }

        public IEnumerable<ResultConfiguration> Configure()
        {
            var results = new List<ResultConfiguration>();

            IDictionary<Application, List<string>> applicationSettings = ConfigurationHelper.GetApplicationSettings();
            IDictionary<string, List<ConfigurationSetting>> configurationSettings = ConfigurationHelper.GetConfigurationSettings();

            if (_backup)
            {
                ConfigurationHelper.CopyConfigurationsFileReference(_rootPath, applicationSettings.Keys);
            }

            foreach (KeyValuePair<Application, List<string>> valuePair in applicationSettings)
            {
                foreach (string value in valuePair.Value)
                {
                    if (configurationSettings.ContainsKey(value))
                    {
                        List<ConfigurationSetting> settings = configurationSettings[value];
                        bool configured = true;
                        string message = string.Empty;

                        try
                        {
                            IList<string> files =
                                ConfigurationHelper.GetFilesRecursively(_rootPath, valuePair.Key);

                            if (files.Count > 0)
                            {
                                string configuratorName = value.Capitalize().Generalize();

                                IConfiguration configurator;
                                _configurators.TryGetValue(configuratorName, out configurator);
                                if (configurator == null)
                                {
                                    throw new UnknownConfiguratorException(configuratorName);
                                }

                                configured = configurator.Configure(files[0], settings);

                                if (files.Count > 1)
                                {
                                    throw new MultipleConfigurationFilesFoundException(files[0], files.Count);
                                }
                            }
                            else
                            {
                                throw new FileNotFoundException(ConfigurationHelper.ConfigurationFileName(valuePair.Key),
                                                                _rootPath,
                                                                valuePair.Key.ID);
                            }
                        }
                        catch (MultipleConfigurationFilesFoundException e)
                        {
                            message = e.Message;
                        }
                        catch (Exception e)
                        {
                            configured = false;
                            message = e.Message;
                        }
                        finally
                        {
                            results.Add(string.IsNullOrEmpty(message)
                                            ? new ResultConfiguration(valuePair.Key.ID, value, configured)
                                            : new ResultConfiguration(valuePair.Key.ID, value, configured, message));
                        }
                    }
                }
            }

            return results;
        }

        #endregion
    }
}